"""
生成器相关的方法
"""

from inspect import (
    Parameter,
    Signature,
    signature,
)
from itertools import islice

from fastapi.routing import APIRoute
from pydantic import (
    BaseModel,
    Field,
    create_model,
)
from pydantic.fields import FieldInfo

from my_typing import *


def chunk_iterable(
    iterable: Iterable[T],
    chunk_size: int,
) -> Generator[list[T], Any, None]:
    """
    将可迭代对象按指定大小分割成多个生成器

    Args:
        iterable: 可迭代对象
        chunk_size: 每个分块的大小，必须为正整数

    Returns:
        分割后的生成器

    Examples:
        >>> list(chunk_iterable(range(10), 3))
        [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
    """

    iterator: Iterator[T] = iter(iterable)

    while chunk := list(islice(iterator, chunk_size)):
        yield chunk


def get_iterable_length(iterable: Iterable) -> tuple[int, Iterator]:
    """
    获取可迭代对象的长度

    Args:
        iterable: 可迭代对象

    Returns:
        (可迭代对象的长度, 生成器)
    """

    items: list = list(iterable)  # 这会消耗生成器
    length: int = len(items)
    new_generator: Iterator = (i for i in items)

    return length, new_generator


class FuncParam(BaseModel):
    """ 函数参数 """

    name: str = Field(..., description="参数名")
    annotation: Any = Field(..., description="参数类型")
    default: Any = Field(..., description="默认值")

    def __init__(self, /, **data: Any) -> None:
        super().__init__(**data)

        if self.annotation == Parameter.empty:
            self.annotation = Any

        if self.default == Parameter.empty:
            self.default = ...


def create_model_from_function(
    func: CallableAny,
    model_name: str = "DynamicModel",
) -> type[BaseModel]:
    """
    根据函数创建模型

    Args:
        func: 函数
        model_name: 模型名

    Returns:
        模型类
    """

    sig: Signature = signature(func)
    model_field_info: dict[str, tuple[type, Any]] = {}
    """
    模型字段属性

    {
        "字段名"": (类型, 默认值),
        "name": (str, ...),
        "age": (int, 18),
    }
    """

    for name, param in sig.parameters.items():
        func_param: FuncParam = FuncParam(
            name=param.name,
            annotation=param.annotation,
            default=param.default,
        )
        model_field_info[func_param.name] = (func_param.annotation, func_param.default)

    return create_model(
        model_name,
        **model_field_info
    )


def create_dynamic_method(request_model: type[T]):
    """ 创建动态方法（用于替代 XXXListRequest 的 from_query 方法，但是似乎在 Swagger 中没有生效...） """

    model_field_dic: dict[str, FieldInfo] = request_model.model_fields

    # 创建参数列表
    parameters: list[Parameter] = [
        Parameter(
            name=name,
            kind=Parameter.KEYWORD_ONLY,
            default=model_field.default,
            annotation=model_field.annotation
        )
        for name, model_field in model_field_dic.items()
    ]

    # 创建签名
    sig = Signature(parameters, return_annotation=T)

    # 创建函数体
    def dynamic_function(**kwargs) -> T:
        bound_args = sig.bind(**kwargs)
        bound_args.apply_defaults()
        # 实际函数逻辑可以在这里实现
        print(f"Called with: {bound_args.arguments}")
        return request_model(**kwargs)

    dynamic_function.__name__ = "from_dict"
    dynamic_function.__doc__ = "Documentation..."
    dynamic_function.__qualname__ = f"{request_model.__name__}.from_dict"
    dynamic_function.__signature__ = sig

    return dynamic_function


def custom_generate_unique_id(route: APIRoute) -> str:
    """ 生成唯一 ID（Tag + 函数名） """

    return f"{route.tags[0]}_{route.name}".lower()
